package source;
import java.util.Vector;


/**
 * An instance of this class represents one square on the map. The tile knows where it is, and what is on it.
 * <ul>
 * <li> ints x and y hold the x and y coordinates of the Tile instance.
 * <li> theUnits is a Unit vector that holds all of the units on the Tile.
 * <li> base holds the base that is on the tile, is initially set to null untill it is settled.
 * <li> onTerrain points to the Terrain type that represents the tile.
 * <li> theItem holds any item that may be on the tile.
 * </ul><p>
 * 
 * @author Tristan Lohman
 * @param testThis
 */
public class Tile {
	
	private final int x; 				/** The X coordinate of the Tile on the map. **/
	private final int y;  				/** The Y coordinate of the Tile on the map **/
	private Vector<Unit> theUnits; 		/** All of the units on the Tile **/
	private Base base; 					/** The Base that is on the tile, if any. **/
	private final Terrain onTerrain; 	/** The reference to the Terrain type of the Tile. **/
	private Item theItem; 				/** Holds the Item that is on the Tile, if any. **/
	private AreaEffect AE;				/** Holds any Area Effect on the Tile **/
	private boolean dirty;				/** True if this tile needs updating */

	/**
	 * Standard Constructor
	 */
	public Tile(int x, int y, Terrain onTerrain){
		this.x = x;
		this.y = y;
		this.theUnits = new Vector<Unit>();
		this.base = null;
		this.onTerrain = onTerrain;
		this.theItem = null;
		this.AE = null;
		dirty = true;
	}
	
	/**
	 * Use this constructor to place an Item on the Tile.
	 * @param theItem = Holds the Item placed on the Tile
	 */
	public Tile(int x, int y, Terrain onTerrain, Item theItem){
		this(x, y, onTerrain);
		this.theItem = theItem;
	} 
	
	/**
	 * Use this constructor to place an Area Effect on the Tile.
	 * @param AE = Holds the Area Effect placed on the Tile
	 */
	public Tile(int x, int y, Terrain onTerrain, AreaEffect AE){
		this(x, y, onTerrain);
		this.AE = AE;
	}	
	
	
	/**
	 * The X coordinate of the Tile.
	 * @return x = the X coordinate of the Tile.
	 */
	public int getX(){return x;}
	
	/**
	 * The Y coordinate of the Tile.
	 * @return y = the Y coordinate of the Tile.
	 */
	public int getY(){return y;}
	
	/**
	 * The Terrain type of the Tile.
	 * @return onTerrain = the Terrain type of the Tile.
	 */
	public Terrain getTerrain(){return onTerrain;}
	
	/**
	 * Removes a Unit from theUnits
	 * @param deleteMe = The Unit to be deleted.
	 * @return True if removed, False if deleteMe was not in theUnits.
	 */
	public boolean removeUnit(Unit deleteMe){
		return theUnits.remove(deleteMe);
	}
	
	public boolean removeBase(Base base){
		if(!(base.equals(this.base)))
			return false;
		base=null;
		return true;
	}
	
	/**
	 * Adds a Unit to the Vector of Units
	 * @param addMe = the Unit to be added to theUnits
	 * @return True as specified by the Vector class
	 */
	public boolean addUnit(Unit addMe){
		return theUnits.add(addMe);
	}
	
	/**
	 * Returns the collection of all of the Units, in a Unit Array. For dsplay purposes.
	 * @return Returns theUnits, in a Unit Array.
	 */
	public Unit[] getAllUnits(){
		Unit[] units = new Unit[0];
		units = theUnits.toArray(units);
		return units;
	}
	
	/**
	 * The Item held on the Tile
	 * @return theItem
	 */
	public Item getTheItem(){
		return theItem;
	}
	
	/**
	 * Changes the Item on the Tile to theItem. Since Tile only holds one Item at a time, this will
	 * destroy the Item currently on the Tile.
	 * @param theItem = the Item to be placed on the Tile
	 */
	public boolean setTheItem(Item theItem){
		if (AE != null) return false;
		this.theItem=theItem;
		return true;
	}
	
	/**
	 * This method is to be called by Colonist when it is creating a base on a planet.
	 * It first checks to make sure there is a Planet on the Tile.
	 * It also checks if there is a Base already on the Tile.
	 * @param base = the Base to be placed on the Tile
	 * @return True if settled successfully, False if not
	 */
	public boolean settle(Base base){
		if (!(this.hasPlanet())) return false;
		if (this.base == null) {
			this.base = base;
			return true;
		}
		return false;
	}
	
	/**
	 * Checks whether or not there is Planet on this Tile.
	 * @return True if it has a Planet, False if not.
	 */
	public boolean hasPlanet(){
		if (onTerrain.getType() == TerrainType.PLANET) return true;
		return false;
	}
	
	public Base getBase(){return base;}
	/**
	 * Set this tile dirty and ready for an update
	 */
	public void setDirty(){
		dirty = true;
	}
	/**
	 * Clear dirty.  Called when this tile has been updated graphically.
	 */
	public void clearDirty(){
		dirty = false;
	}
	/**
	 * Checks if this tile is dirty.
	 * @return whether or not this tile is dirty
	 */
	public boolean isDirty(){
		return dirty;
	}
	
	/**
	 * 
	 * @return true if the Tile has Units on it; false otherwise
	 */
	public boolean hasUnits() {
		return this.theUnits.size() > 0;
	}
	
	/**
	 * Determines the ID of the Player that owns the units located on this
	 * tile.
	 * @return int - the Player ID of the Player owning the Units on this Tile;
	 * returns -1 if there are no units on this Tile.
	 */
	public int getUnitPlayerID() {
		if (this.hasUnits()) {
			return this.theUnits.get(0).getPlayer().getID();
		}
		else return -1;
	}
	
	/**
	 * If a Unit has moved onto this Tile, then the Item needs to be removed after giving it's bonus if it is
	 * an one-shot Item.
	 * @return true if the Item was removed from Tile; false otherwise
	 */
	public boolean removeItem() {
		if (this.theItem.getType() != ItemType.NOTPASSABLE || this.theItem.getIsOneShot()) {
			this.theItem = null;
			return true;
		}
		return false;
	}
	
	/**
	 * Asks this Tile for it's AreaEffect object
	 * @return AreaEffect owned by this Tile
	 */
	public AreaEffect getAreaEffect() {
		return this.AE;
	}
	
	public void setAreaEffect(AreaEffect ae){
		this.AE = ae;
	}
}
